Repository navigation
fix(mcpserver): preserve Annotated/Field metadata for dict[str, T] return types - #2939
anneheartrecord wants to merge 2 commits into
Conversation
…turn types When a tool returns `Annotated[dict[str, T], Field(description="...")]`, the `_try_create_model_and_schema` dict branch was passing the unwrapped `type_expr` (i.e. `dict[str, T]`) to `_create_dict_model` instead of `original_annotation`, so any `Field` description or other Pydantic metadata was dropped from the output schema. Fix by passing `original_annotation` so the `RootModel` picks it up. Fixes modelcontextprotocol#2935
Pre-commit ruff-format check failed because the return type annotation for get_headers() in the test exceeded line-length limits. Wrap it to three lines to satisfy the formatter.
|
Fixed the pre-commit failure — ruff-format wrapped a long return-type annotation in the test file. All other checks were already green. |
|
Nice catch! Using |
|
@maxisbey — this has been open since Jun 21 with no maintainer pass, so surfacing it. It should be a fast one: It answers a TODO this repo already wrote. # TODO: should we use the original annotation? We are losing any potential `Annotated`
# metadata for Pydantic here:
model = _create_dict_model(func_name, type_expr)The answer is yes, and that is the whole change — passing State: +30/-3 across 2 files, all 27 checks green, still Independent read: @itxaiohanglover looked at it on Jun 26 and reached the same conclusion about No objection if you would rather resolve the TODO differently — if you prefer the metadata to be dropped deliberately and the comment removed instead, say so and I will close this. I mostly want the TODO to stop being ambiguous either way. |
|
Thanks for the PR, and sorry it sat here without a proper review. We're closing most of the open PR backlog. v2 is out and changed a lot of the SDK, so many older PRs no longer apply as written, and we're a small team that realistically doesn't have the capacity to work through the rest. If this still matters to you on v2, the most useful thing you can do is open an issue (or comment on the existing one) with your use case and a repro. Hearing why it matters to you is what we use to decide what to prioritise. |
Summary
When a tool declares a
dict[str, T]return type wrapped inAnnotatedwithPydantic
Fieldmetadata (e.g. a description), that metadata was silently droppedfrom the generated output schema.
Root cause
In
_try_create_model_and_schema, thedict[str, T]branch called_create_dict_model(func_name, type_expr)wheretype_expris theAnnotated-stripped type. The existing TODO comment on that line even flaggedthe issue. The fix is to pass
original_annotationinstead, soRootModel[Annotated[dict[str, T], Field(...)]]picks up the metadata.Changes
src/mcp/server/mcpserver/utilities/func_metadata.py: passoriginal_annotationinstead of
type_exprto_create_dict_model; replace TODO comment with aclarifying one
tests/server/mcpserver/test_func_metadata.py: addtest_structured_output_dict_str_preserves_annotated_metadataregression testcovering
Field(description=...)andField(description=..., title=...)Fixes #2935